home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / manage / snmp / kip / etc / atalkad.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-01-17  |  25.2 KB  |  1,100 lines

  1. #ifndef lint
  2. static char sccsid[] = "@(#)atalkad.c    1.2 (Stanford) 9/87";
  3. #endif
  4.  
  5. /*
  6.  * Appletalk administration daemon.
  7.  *
  8.  * Answers request packets from client appletalk gateways by supplying
  9.  * the appletalk-to-ip network configuration table and the local
  10.  * appletalk gateway configuration information.
  11.  */
  12.  
  13. /*
  14.  * (C) 1986, Stanford Univ.  CSLI.
  15.  * May be used but not sold without permission.
  16.  */
  17.  
  18.  
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <sys/socket.h>
  22. #include <sys/ioctl.h>
  23. #include <sys/file.h>
  24. #include <sys/time.h>
  25. #include <netinet/in.h>
  26. #define iaddr_t long
  27. #include "gwctl.h"
  28. #include "ab.h"
  29.  
  30. #include <signal.h>
  31. #include <stdio.h>
  32. #include <strings.h>
  33. #include <errno.h>
  34. #include <ctype.h>
  35. #include <netdb.h>
  36.  
  37. /* for 4.2 systems */
  38. #ifndef FD_SETSIZE
  39. # define FD_SETSIZE sizeof(int)*8
  40. # define NFDBITS sizeof(int)*8
  41. # define howmany(x,y) (1)
  42. # define FD_SET(n, p)  (p)->fds_bits[0] |= (1<<(n))
  43. # define FD_CLR(n, p)  (p)->fds_bits[0] &= ~(1<<(n))
  44. # define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n)))
  45. # define FD_ZERO(p) bzero((char *)p, sizeof(*p))
  46. #endif
  47.  
  48. #ifndef ATALKATAB
  49. #define    ATALKATAB "/etc/atalkatab"
  50. #endif
  51. #ifndef ATALKALOG
  52. #define    ATALKALOG "/usr/adm/atalkalog"
  53. #endif
  54. #ifndef ATALKAPID
  55. #define    ATALKAPID "/usr/adm/atalkapid"
  56. #endif
  57.  
  58. int    debug;
  59. extern    int errno;
  60. struct    sockaddr_in sin = { AF_INET };
  61. int    s;        /* socket fd */
  62. struct    sockaddr_in fsin; /* foreign sockaddr_in */
  63. int    fsinlen;
  64. int    sig, sigint(), sighup();
  65. struct aaconf aa;    /* receive packet */
  66. struct aaconf aas;    /* send packet */
  67. struct timeval tvwait;    /* timer for select */
  68.  
  69. /* Mask of high 3 bytes of a network address */
  70. iaddr_t node_mask;
  71.   
  72. /*
  73.  * Globals below are associated with the atalka database file (atalkatab).
  74.  */
  75. char    *atalkatab = ATALKATAB;
  76. char    *atalkalog = ATALKALOG;
  77. char    *atalkapid = ATALKAPID;
  78. FILE    *fp;
  79. char    line[256];    /* line buffer for reading atalkatab */
  80. char    *linep;        /* pointer to 'line' */
  81. int    linenum;    /* current line number in atalkatab */
  82.  
  83. #define    NANETS    64    /* max number of 'anets' structs */
  84.  
  85. struct anets {
  86.     u_short    net;        /* atalk net */
  87.     u_char    flags;        /* flags, see aroute* in gwctl.h */
  88.     u_char    confsize;    /* size of databytes in conf below */
  89.     iaddr_t    iaddr;        /* ip address */
  90.     char    zone[32];    /* zone name */
  91.     char    conf[64];    /* configuration info, if kbox */
  92. } anets[NANETS];
  93.  
  94. /* Internal format of conf structure */
  95. struct conf {
  96.     iaddr_t    ipbroad;        /* broadcast addr on ether */
  97.     iaddr_t    ipname;            /* address of name server */
  98.     iaddr_t    ipdebug;        /* address of debug host */
  99.     iaddr_t    ipfile;            /* address of file server */
  100.     u_long    ipother[4];        /* other addresses passed via IPGP */
  101. #define ipsmask anetet                /* old use for this field */
  102.     u_short    anetet;                /* ethertalk net number of enet */
  103. #define ipsshift startddpWKSUnix    /* old: subnet shift (unused) */
  104.     u_short    startddpWKSUnix;    /* start of unix WKS udp ports */
  105.     u_long    flags;            /* various bit flags */
  106. #define    conf_stayinzone 0x1        /* no looking at other zones */
  107. #define conf_laserfilter 0x2        /* NBP filtering for LaserWriters */
  108. #define    conf_tildefilter 0x4        /* NBP filtering, "name~" */
  109.     u_short    ipstatic;        /* number of static IP addrs */
  110.     u_short    ipdynamic;        /* number of dynamic IP addrs */
  111.     u_short    atneta;            /* atalk net #, appletalk */
  112.     u_short    atnete;            /* atalk net #, ethernet */
  113. } conf_proto;
  114.  
  115. int    nanets;        /* current number of anets */
  116. long    modtime;    /* last modification time of atalkatab */
  117. long size;        /* last known size of file */
  118. char    aroutes[512];    /* route tuples built by buildart() */
  119. int    arouteslen;
  120. char    azones[512];    /* zone table built by buildzone() */
  121. int    azoneslen;
  122.  
  123. int scanonly = 0;
  124.  
  125.  
  126. usage()
  127. {
  128.   printf("usage: atalkad [-c filename] [-debug] [route|boot|exit]\n");
  129.   printf("usage:  -c means check file\n");
  130.   exit(1);
  131. }
  132.  
  133. main(argc, argv)
  134.     char *argv[];
  135. {
  136.     register int n;
  137.     FILE *filep;
  138.     int pid;
  139.  
  140.     for (argc--, argv++ ; argc > 0 ; argc--, argv++) {
  141.         if (argv[0][0] == '-') {
  142.             switch (argv[0][1]) {
  143.             case 'd':
  144.                 debug++;
  145.                 break;
  146.             case 'c':
  147.                 if (argv[0][2]) {
  148.                   atalkatab = argv[0]+2;
  149.                 } else if (argc > 1 && argv[1]) {
  150.                   atalkatab = argv[1];
  151.                   argc--, argv++;
  152.                 }
  153.                 scanonly++;
  154.                 break;
  155.             default:
  156.                 usage();
  157.             }
  158.             continue;
  159.         }
  160.         if (scanonly)
  161.           usage();
  162.         if (strcmp(argv[0], "boot") == 0)
  163.             sig = SIGINT;
  164.         else if (strcmp(argv[0], "route") == 0)
  165.             sig = SIGHUP;
  166.         else if (strcmp(argv[0], "exit") == 0)
  167.             sig = SIGKILL;
  168.         else
  169.           usage();
  170.         if ((filep = fopen(atalkapid, "r")) == NULL
  171.             || fscanf(filep, "%d", &pid) != 1
  172.             || kill(pid, sig) < 0) {
  173.             printf("failed to send signal to daemon\n");
  174.             exit(1);
  175.         } else {
  176.             printf("sent signal to daemon\n");
  177.             exit(0);
  178.         }
  179.     }
  180.     
  181.     if (scanonly) {
  182.       readtab();
  183.       dumptab();
  184.       exit(0);
  185.     }
  186.  
  187.     if (debug == 0) {
  188.         int t, f;
  189.         if (fork())
  190.             exit(0);
  191.         for (f = 0; f < 10; f++)
  192.             (void) close(f);
  193.         (void) open("/", 0);
  194.         (void) dup2(0, 1);
  195.         (void) dup2(0, 2);
  196.         t = open("/dev/tty", 2);    
  197.         if (t >= 0) {
  198.             ioctl(t, TIOCNOTTY, (char *)0);
  199.             (void) close(t);
  200.         }
  201.     }
  202.  
  203.     log("###    ATALKA daemon starting");
  204.     pid = getpid();
  205.     if ((filep = fopen(atalkapid, "w")) == NULL) {
  206.         log("couldnt create pid file %s\n", atalkapid);
  207.         exit(1);
  208.     }
  209.     fprintf(filep, "%d", pid); 
  210.     fclose(filep);
  211.     signal(SIGHUP, sighup);
  212.     signal(SIGINT, sigint);
  213.  
  214.     while ((s = socket(AF_INET, SOCK_DGRAM, 0, 0)) < 0) {
  215.         log("socket call failed");
  216.         sleep(5);
  217.     }
  218.     sin.sin_port = htons(aaPort);
  219.     if (bind(s, (caddr_t)&sin, sizeof (sin), 0) < 0) {
  220.         log("bind call failed");
  221.         exit(1);
  222.     }
  223.  
  224.     /* fill in node mask in a machine independent manner */
  225.     node_mask = inet_addr("255.255.255.0");
  226.  
  227.     readtab();
  228.     for (;;) {
  229.         fsinlen = sizeof (fsin);
  230.         n = recvfrom(s, (caddr_t)&aa, sizeof aa,
  231.             0, (caddr_t)&fsin, &fsinlen);
  232.         if (n < 0) {
  233.             if (errno != EINTR) {
  234.                 log("recv failed");
  235.                 exit(1);
  236.             }
  237.             readtab();
  238.             sendall(sig);
  239.             continue;
  240.         }
  241.         if (n < aaconfMinSize || ntohl(aa.magic) != aaMagic)
  242.             continue;
  243.         readtab();
  244.         sendreply();
  245.     }
  246. }
  247.  
  248.  
  249. /*
  250.  * Interrupts are used to signal type of sendall().
  251.  */
  252. sighup() { sig = aaROUTEI; }
  253. sigint() { sig = aaRESTART; }
  254.  
  255.  
  256. /*
  257.  * Send reply to packet aa.
  258.  */
  259. sendreply()
  260. {
  261.     register struct anets *an;
  262.     register n;
  263.  
  264.     switch (aa.type) {
  265.     case aaCONF:
  266.         for (an = &anets[0], n = 0 ; n < nanets ; an++, n++)
  267.             if (an->iaddr == aa.ipaddr && an->confsize &&
  268.                 (an->flags & arouteKbox) &&
  269.                 (an->flags & arouteEtalk) == 0)
  270.                 goto found;
  271.         log("aaCONF from %s ***** not in table", inet_ntoa(aa.ipaddr));
  272.         return;
  273. found:
  274.         log("aaCONF to %s", inet_ntoa(aa.ipaddr));
  275.         n = an->confsize;
  276.         bcopy(an->conf, aa.stuff, n);
  277.         break;
  278.     case aaZONE:
  279.         log("aaZONE to %s", inet_ntoa(aa.ipaddr));
  280.         n = azoneslen;
  281.         bcopy(azones, aa.stuff, n);
  282.         break;
  283.     case aaZONEQ:
  284.         log("aaZONEq from %s", inet_ntoa(aa.ipaddr));
  285.         if ((n = zipinput()) <= 0)
  286.           return;    /* drop */
  287.         break;
  288.     case aaROUTEI:
  289.         log("aaROUTEI to %s", inet_ntoa(aa.ipaddr));
  290.         n = arouteslen;
  291.         bcopy(aroutes, aa.stuff, n);
  292.         break;
  293.     default:
  294.         /* don't reply here! */
  295.         return;
  296.     }
  297.     aa.count = htons(n);
  298.     sendto(s, (caddr_t)&aa, aaconfMinSize + n, 0,
  299.            &fsin, sizeof fsin);
  300. }
  301.  
  302.  
  303. char *
  304. netstring(n)
  305. u_short n;
  306. {
  307.   int net;
  308.   static char mynetstr[30];
  309.  
  310.   net = ntohs(n);
  311.   sprintf(mynetstr, "%d.%d", (net>>8) & 0xff, net & 0xff);
  312.   return(mynetstr);
  313. }
  314.  
  315. /*
  316.  * return pointer to zone name
  317.  * NULL if none
  318. */
  319. char *
  320. zoneof(net)
  321. u_short net;
  322. {
  323.   register struct anets *an;
  324.   int n;
  325.  
  326.   for (an = &anets[0], n=0 ; n < nanets ; an++, n++)
  327.     if (net == an->net)
  328.       return(an->zone);
  329.   return(NULL);
  330. }
  331.  
  332. /*
  333.  * return a value that is always printable
  334.  *
  335. */
  336. char *
  337. pzoneof(net)
  338. u_short net;
  339. {
  340.   char *p = zoneof(net);
  341.   return(p == NULL ? "unknown" : p);
  342. }
  343.  
  344. dumptab()
  345. {
  346.   register struct anets *an;
  347.   register n, size;
  348.   char *hostnameof();
  349.   struct conf *conf;
  350.   iaddr_t rs, re;
  351.  
  352.   size = 0;
  353.   for (an = &anets[0], n = 0 ; n < nanets ; an++, n++) {
  354.     printf("Route %s %s, ", netstring(an->net), an->zone);
  355.     if ((an->flags & arouteKbox) && (an->flags & arouteEtalk) == 0)
  356.       printf(" Kinetics box");
  357.     if (an->flags & arouteCore)
  358.       printf(" core gateway");
  359.     if (an->flags & arouteHost)
  360.       printf(" host is redirector");
  361.     if (an->flags & arouteNet)
  362.       if (an->flags & arouteBMask)
  363.     printf(" net %d", an->flags & arouteBMask);
  364.       else
  365.     printf(" net 0: host is client");
  366.     if ((an->flags & (arouteKbox|arouteEtalk)) == (arouteKbox|arouteEtalk))
  367.       printf(" EtherTalk");
  368.     printf(" at %s", hostnameof(an->iaddr));
  369.     putchar('\n');
  370.     if ((an->flags & arouteKbox) && (an->flags & arouteEtalk) == 0) {
  371.       conf = (struct conf *)an->conf;
  372.       printf("\tIP Broadcast: %s, ", inet_ntoa(conf->ipbroad));
  373.       if (conf->ipname == conf->ipdebug) {
  374.     printf("IP name and debug: %s\n", hostnameof(conf->ipname));
  375.     printf("\tIP file server (unused)", hostnameof(conf->ipfile));
  376.       } else {
  377.     printf("IP name: %s\n",hostnameof(conf->ipname));
  378.     printf("\tIP debug %s, ", hostnameof(conf->ipdebug));
  379.     printf("IP file server (unused)", hostnameof(conf->ipfile));
  380.       }
  381.       if (ntohl(conf->flags) & conf_stayinzone)
  382.     printf(", marked stay in zone");
  383.       if (ntohl(conf->flags) & conf_laserfilter)
  384.     printf(", laserwriters stay in zone");
  385.       if (ntohl(conf->flags) & conf_tildefilter)
  386.     printf(", tilde marked names stay in zone");
  387.       putchar('\n');
  388.       if (conf->startddpWKSUnix == htons(defddpWKSUnix))
  389.     printf("\tUDP Port range for WKS starts at %d (old range)\n",
  390.            defddpWKSUnix);
  391.       else
  392.     printf("\tUDP Port range for WKS starts at %d\n",
  393.            ntohs(conf->startddpWKSUnix));
  394. #ifdef SHORTFORMAT
  395.       if (conf->ipstatic)
  396.     printf("\t%d ", ntohs(conf->ipstatic));
  397.       else
  398.     printf("\tNo");
  399.       printf(" static ip addresses, ");
  400.       if (conf->ipdynamic)
  401.     printf("\t%d ", ntohs(conf->ipdynamic));
  402.       else
  403.     printf("\tNo");
  404.       printf(" dynamic ip addresses\n");
  405. #else
  406.       if (conf->ipstatic) {
  407.     re = rs = ntohl(an->iaddr)+1;
  408.     re += (ntohs(conf->ipstatic)-1);
  409.     printf("\tIP static address range: %s",
  410.            inet_ntoa(htonl(rs)));
  411.     printf(" %s\n",inet_ntoa(htonl(re)));
  412.       } else {
  413.     printf("\tIP static address range: empty\n");
  414.     re = ntohl(an->iaddr);
  415.       }
  416.       if (conf->ipdynamic) {
  417.     re = rs = re+1;
  418.     re += (ntohs(conf->ipdynamic)-1);
  419.     printf("\tIP dynamic address range: %s",
  420.            inet_ntoa(htonl(rs)));
  421.     printf(" %s\n",inet_ntoa(htonl(re)));
  422.       } else {
  423.     printf("\tIP dynamic address range: empty\n");
  424.     re = ntohl(an->iaddr);
  425.       }
  426.  
  427. #endif
  428.       printf("\tKbox interfaces:\n");
  429.       printf("\t\tlocaltalk: %s zone %s\n", netstring(conf->atneta),
  430.          pzoneof(conf->atneta));
  431.       printf("\t\tKIP: %s zone %s\n", netstring(conf->atnete),
  432.          pzoneof(conf->atnete));
  433.       if (conf->anetet) {
  434.     printf("\t\tEtherTalk: %s zone %s\n", netstring(conf->anetet),
  435.            pzoneof(conf->anetet));
  436.       }
  437.     }
  438.   }
  439. }
  440.  
  441. /*
  442.  * Build arouteTuple's into area provided by caller.
  443.  * Return byte count of tuples deposited.
  444.  */
  445. buildart(at, maxsize)
  446.     register struct arouteTuple *at;
  447.         int maxsize;
  448. {
  449.     register struct anets *an;
  450.     register n, size;
  451.  
  452.     size = 0;
  453.     for (an = &anets[0], n = 0 ; n < nanets ; an++, n++, at++) {
  454.         size += sizeof *at;
  455.         at->node = an->iaddr;
  456.         at->net = an->net;
  457.         at->flags = an->flags;
  458.         at->hops = 0; /* start at one - incremented in gateway */
  459.     }
  460.     log("art build: %d entries, %d maximum",
  461.         size/(sizeof(struct arouteTuple)),
  462.         maxsize/(sizeof(struct arouteTuple)));
  463.     if (size > maxsize)
  464.         log("art build: routing table too big!!");
  465.     if (size > (maxsize - 10) )
  466.         log("art build: routing table size %d is near maximum of %d",
  467.             size, maxsize );
  468.     return (size);
  469. }
  470.  
  471.  
  472. #define    MAXZ    32
  473.  
  474. /*
  475.  * Build zones structure to be returned by aaZONE.
  476.  */
  477. buildzones(az, azlen)
  478.     char *az;
  479.     int azlen;
  480. {
  481.     char zname[MAXZ][33];
  482.     int nzname = 0;
  483.     char netzone[NANETS];
  484.     register i, iz, n;
  485.     register char *cp;
  486.     int zonenamelen = 0;
  487.  
  488.     /* make a pass thru anets, finding all unique zone names. */
  489.  
  490.     for (i = 0 ; i < nanets ; i++) {
  491.         for (iz = 0 ; iz < nzname ; iz++)
  492.             if (strcmp(anets[i].zone, zname[iz]) == 0)
  493.                 goto found;
  494.         /* not found, make a new name */
  495.         strcpy(zname[iz], anets[i].zone);
  496.         zonenamelen += strlen(zname[iz]) + 1;
  497.         netzone[i] = iz;
  498.         nzname++;
  499.         continue;
  500.         /* found it, note the zname index */
  501. found:
  502.         netzone[i] = iz;
  503.     }
  504.     /*
  505.      * Build structure to send to gateway.  Looks like:
  506.      * net# net# ... 0 zonename
  507.      * net# net# ... 0 zonename
  508.      * 0xFFFF.
  509.      */
  510.     cp = az;
  511.     for (iz = 0 ; iz < nzname ; iz++) {
  512.         for (i = 0 ; i < nanets ; i++) {
  513.             if (netzone[i] != iz)
  514.                 continue;
  515.             /* anets[].net has been swapped by readtab */
  516.             *cp++ = (ntohs(anets[i].net) >> 8);
  517.             *cp++ = ntohs(anets[i].net);
  518.         }
  519.         *cp++ = 0;  *cp++ = 0;
  520.         *cp++ = n = strlen(zname[iz]);
  521.         bcopy(zname[iz], cp, n);
  522.         cp += n;
  523.     }
  524.     *cp++ = 0xFF;  *cp++ = 0xFF;
  525.     n = cp - az;        /* length of table */
  526.     if (n > sizeof(azones)) {
  527.       log("buildzones: ZIP table too large");
  528.      log("buildzones: don't worry if you are using a KIP later than 1/88");
  529.     } else if (n > (sizeof(azones)-10))
  530.       log("buildzones: ZIP table size %d approaching maximum of %d",
  531.           n, sizeof(azones));
  532.     log("zone names take %d bytes in gateway");
  533.     return (n);
  534. }
  535.  
  536.  
  537. /*
  538.  * Send aaRESTART or aaROUTEI to all gateways.
  539.  */
  540. sendall(sig)
  541. {
  542.     register struct anets *an;
  543.     register n;
  544.     int trys, count, rcount;
  545.     fd_set fds;
  546.     struct sockaddr_in tsin;
  547.  
  548.     tsin = sin;
  549.     log("sendall(%s)", sig == aaRESTART ? "aaRESTART" : "aaROUTEI");
  550.     aas.magic = htonl(aaMagic); /* setup send packet */
  551.     aas.type = sig;
  552.     aas.flags = 0;
  553.     if (sig == aaROUTEI) {
  554.         bcopy(aroutes, aas.stuff, arouteslen);
  555.         count = arouteslen;
  556.     } else {
  557.         count = 0;
  558.     }
  559.     aas.count = htons(count);
  560.     count += aaconfMinSize;
  561.     /*
  562.      * send to each kbox in the table.
  563.      */
  564.     for (an = &anets[0], n = 0 ; n < nanets ; an++, n++) {
  565.         if ((an->flags & arouteKbox) == 0 || (an->flags & arouteEtalk))
  566.             continue;
  567.         trys = 0;
  568.         tsin.sin_addr.s_addr = an->iaddr;
  569.         sendto(s, (caddr_t)&aas, count, 0, &tsin, sizeof tsin);
  570.         /*
  571.          * receive until we get a good reply or timeout.
  572.          */
  573.         for (;;) {
  574.             FD_ZERO(&fds);
  575.             FD_SET(s, &fds);
  576.             tvwait.tv_sec = 2;  /* select waits 2 seconds */
  577.             tvwait.tv_usec = 0;
  578.             if (select(NFDBITS, &fds, 0, 0, &tvwait) != 1) {
  579.                 /* timeout */
  580.                 if (++trys < 4) {
  581.                     sendto(s, (caddr_t)&aas, 
  582.                         count, 0, &tsin, sizeof tsin);
  583.                     continue;
  584.                 }
  585.                 log("no response from %s",
  586.                     inet_ntoa(an->iaddr));
  587.                 break;
  588.             }
  589.             fsinlen = sizeof fsin;
  590.             rcount = recvfrom(s, (caddr_t)&aa, sizeof aa,
  591.                 0, (caddr_t)&fsin, &fsinlen);
  592.             if (rcount < 0) {
  593.                 if (errno == EINTR)
  594.                     continue;
  595.                 log("recv failed");
  596.                 exit(1);
  597.             }
  598.             if (rcount < aaconfMinSize 
  599.                 || ntohl(aa.magic) != aaMagic)
  600.                 continue;
  601.             if (aa.ipaddr != an->iaddr) {
  602.                 sendreply();
  603.                 continue;
  604.             }
  605.             /* our request got thru! */
  606.             sendreply();
  607.             break;
  608.         }
  609.     }
  610.     log("sendall(%s) complete",sig==aaRESTART ? "aaRESTART" : "aaROUTEI");
  611. }
  612.  
  613. /*
  614.  * check over configurations
  615.  *
  616. */
  617. checkconfigs()
  618. {
  619.   int  i;
  620.   struct anets *an;
  621.   struct conf *cp;
  622.   int rangestart = 0;
  623.   int rangeconflict = 0;
  624.   int badrange = 0;
  625.  
  626.   for (an = anets, i = 0; i < nanets; i++, an++) {
  627.     if (an->confsize >= sizeof(struct conf)) {
  628.       cp = (struct conf *)an->conf;
  629.       if (!cp->startddpWKSUnix) {
  630.     cp->startddpWKSUnix = htons(defddpWKSUnix);
  631.     if (rangestart) {
  632.       if (rangestart != cp->startddpWKSUnix)
  633.         rangeconflict = 1;
  634.     } else rangestart = cp->startddpWKSUnix;
  635.       } else {
  636.     if (rangestart) {
  637.       if (rangestart != cp->startddpWKSUnix)
  638.         rangeconflict = 1;
  639.     } else rangestart = cp->startddpWKSUnix;
  640.       }
  641.     }
  642.   }
  643.   rangestart = ntohs(rangestart);
  644.   if (rangeconflict)
  645.     log("Conflict in UDP WKS range start!");
  646.   else if (rangestart != 200 && rangestart != defddpWKSUnix) {
  647.     log("WARNING - UDP WKS range start %d is non-standard",
  648.     ntohs(rangestart));
  649.   }
  650. }
  651.  
  652. /*
  653.  * Read atalkatab database file.  Avoid rereading the file if the
  654.  * write date hasnt changed since the last time we read it.
  655.  */
  656. readtab()
  657. {
  658.     struct stat sbuf1, sbuf;
  659.     register char *sp, *cpp;
  660.     int v;
  661.     register i;
  662.     char st[128], *cp;
  663.     register struct anets *an;
  664.     iaddr_t iaddr;
  665.  
  666.     if (fp == 0) {
  667.         if ((fp = fopen(atalkatab, "r")) == NULL) {
  668.             log("can't open %s", atalkatab);
  669.             exit(1);
  670.         }
  671.     }
  672.     if (fstat(fileno(fp), &sbuf1) < 0)
  673.       goto reopen;
  674.     if (stat(atalkatab, &sbuf) < 0)
  675.       goto reopen;
  676.     if (sbuf1.st_dev == sbuf.st_dev && /* different... */
  677.         sbuf1.st_ino == sbuf.st_ino && /* ...file */
  678.         sbuf1.st_size == size && /* nec? */
  679.         sbuf.st_size == size &&
  680.         sbuf1.st_mtime == modtime && /* nec? */
  681.         sbuf.st_mtime == modtime)
  682.       return;
  683. reopen:    
  684.       if (fp)
  685.           fclose(fp);
  686.     if ((fp = fopen(atalkatab, "r")) == NULL) {
  687.         log("can't open %s", atalkatab);
  688.         exit(1);
  689.     }
  690.     fstat(fileno(fp), &sbuf);
  691.     log("(re)reading %s", atalkatab);
  692.     modtime = sbuf.st_mtime;
  693.     size = sbuf.st_size;
  694.     nanets = 0;
  695.     an = &anets[-1];
  696.     linenum = 0;
  697.  
  698.     /*
  699.      * read and parse each line in the file.
  700.      */
  701.     for (;;) {
  702.         if (fgets(line, sizeof line, fp) == NULL)
  703.             break;    /* done */
  704.         if ((i = strlen(line)))
  705.             line[i-1] = 0;    /* remove trailing newline */
  706.         linep = line;
  707.         linenum++;
  708.         if (line[0] == '#' || line[0] == 0)
  709.             continue;    /* skip comment lines */
  710.         if (line[0] == ' ' || line[0] == '\t') 
  711.             goto confinfo;
  712.         /*
  713.          * lines not beginning with white space 
  714.          * represent a new net #
  715.          */
  716.         if (++nanets > NANETS) {
  717.             log("'anets' table length exceeded");
  718.             exit(1);
  719.         }
  720.         an++;
  721.         cp = an->conf;    /* store following lines here */
  722.         an->confsize = 0;
  723.         getfield(st, sizeof st);
  724.         an->net = htons(getashort(st));
  725.         getfield(st, sizeof st);
  726.         i = 0;
  727.         /* parse flags */
  728.         for (cpp = st ; *cpp ; cpp++) {
  729.             if (isupper(*cpp))
  730.                 *cpp = tolower(*cpp);
  731.             switch (*cpp) {
  732.             case 'c':
  733.                 i |= arouteCore;  break;
  734.             case 'k':
  735.                 i |= arouteKbox;  break;
  736.             case 'h':
  737.                 i |= arouteHost;  break;
  738.             case 'n':
  739.                 i |= arouteNet;  break;
  740.                  case 'e':
  741.                 i |= (arouteEtalk|arouteKbox); break;
  742.             case '0': case '1': case '2': case '3':
  743.                 i |= (*cpp - '0');  break;
  744.             default:
  745.                 log("bad switch %s, linenum %d", st, linenum);
  746.             }
  747.         }
  748.         an->flags = i;
  749.         getfield(st, sizeof st);
  750.         an->iaddr = getiaddr(st);
  751.         getfield(an->zone, sizeof(an->zone));
  752.         continue;
  753. confinfo:
  754.         /*
  755.          * lines beginning with white space
  756.          * are configuration data for gateway.
  757.          */
  758.         for (;;) {    /* for each field in line */
  759.             int len;
  760.             getfield(st, sizeof st);
  761.             sp = st;
  762.             if (*sp == 0)
  763.                 break;
  764.             if (isupper(*sp))
  765.                 *sp = tolower(*sp);
  766.             switch (*sp++) {
  767.             case '%':
  768.               /* escape code, one of 'n' */
  769.               if (isupper(*sp))
  770.                 *sp = tolower(*sp);
  771.               switch (*sp++) {
  772.                 int flag;
  773.               case 'n':
  774.                 /* decide which type of network based on */
  775.                 /* the offset in the config structure */
  776.                 if (cp - an->conf ==
  777.                 (char *)&conf_proto.atnete-(char *)&conf_proto)
  778.                   flag = arouteNet;
  779.                 else if (cp - an->conf ==
  780.                 (char*)&conf_proto.anetet-(char*)&conf_proto)
  781.                   flag = arouteKbox|arouteEtalk;
  782.                 else if (cp - an->conf ==
  783.                 (char*)&conf_proto.atneta-(char*)&conf_proto)
  784.                   flag = arouteKbox;
  785.                 else {
  786.                   log("%%N at unexpected offset %d, line %d\n",
  787.                   cp - an->conf, linenum);
  788.                   flag = arouteKbox;
  789.                 }
  790.  
  791.                 if ((*(short *)cp = 
  792.                  getanet(flag, an->iaddr)) == 0)
  793.                   log("%%N not set, line %d\n", linenum);
  794.                 cp += 2;
  795.                 an->confsize += 2;
  796.                 break;
  797.  
  798.               default:
  799.                 log("bad field type %s, linenum %d", st, linenum);
  800.                 break;
  801.               }
  802.               break;
  803.               
  804.             case 'i':
  805.                 /* IP address name or number */
  806.                 iaddr = getiaddr(sp);
  807.                 bcopy((caddr_t)&iaddr, cp, sizeof iaddr);
  808.                 cp += sizeof iaddr;
  809.                 an->confsize += sizeof iaddr;
  810.                 break;
  811.  
  812.             case 'l':
  813.                 if ((int)cp & 1) 
  814.                     goto badalign;
  815.                 *(long *)cp = htonl(atoii(sp));
  816.                 cp += 4;
  817.                 an->confsize += 4;
  818.                 break;
  819.  
  820.             case 's':
  821.                 if ((int)cp & 1) 
  822.                     goto badalign;
  823.                 *(short *)cp = htons(getashort(sp));
  824.                 cp += 2;
  825.                 an->confsize += 2;
  826.                 break;
  827.             
  828.             case 'c':
  829.                 *cp = atoii(sp);
  830.                 cp++;
  831.                 an->confsize++;
  832.                 break;
  833.  
  834.             case '"':
  835.                 len = strlen(sp) - 1; /* drop trailing " */
  836.                 bcopy(sp, cp, len);
  837.                 cp += len;
  838.                 *cp++ = 0;
  839.                 len++;
  840.                 an->confsize += len;
  841.                 break;
  842.  
  843.             case '\'': /* pascal string */
  844.                 len = strlen(sp) - 1; /* drop trailing ' */
  845.                 *cp++ = len;
  846.                 bcopy(sp, cp, len);
  847.                 cp += len;
  848.                 len++; /* skip over length field */
  849.                 *cp++ = 0;
  850.                 len++;
  851.                 an->confsize += len;
  852.                 break;
  853.             
  854.             default:
  855.                 log("bad field type %s, linenum %d",
  856.                     st, linenum);
  857.                 break;
  858.             }
  859.             continue;    /* get next field in line */
  860. badalign:
  861.             log("long/short bad alignment %s, linenum %d",
  862.                 st, linenum);
  863.             break;
  864.         }
  865.         /* get next line */
  866.     }
  867.     /* end of file */
  868.     checkconfigs();
  869.     arouteslen = buildart((struct arouteTuple *)aroutes, sizeof aroutes);
  870.     azoneslen = buildzones(azones, sizeof azones);
  871. }
  872.  
  873.  
  874. /*
  875.  * Get next field from 'line' buffer into 'str'.  'linep' is the 
  876.  * pointer to current position.  No imbeded spaces are allowed in the
  877.  * fields;  however, an underscore '_' will convert to a space.  (To get
  878.  * a real underscore, double it.)
  879.  */
  880. getfield(str, len)
  881.     char *str;
  882. {
  883.     register char *cp = str;
  884.     register und;
  885.  
  886.     for ( ; *linep && (*linep == ' ' || *linep == '\t') ; linep++)
  887.         ;    /* skip spaces/tabs */
  888.     if (*linep == 0 || *linep == '#') {
  889.         *cp = 0;
  890.         return;
  891.     }
  892.     und = 0;
  893.     len--;    /* save a spot for a null */
  894.     for ( ; *linep && *linep != ' ' 
  895.         && *linep != '\t' && *linep != '#' ; linep++) {
  896.         if (*linep == '_') {
  897.             if (und) {
  898.                 und = 0;  cp--;  len++;
  899.             } else {
  900.                 und++;  *linep = ' ';
  901.             }
  902.         } else {
  903.             und = 0;
  904.         }
  905.         *cp++ = *linep;
  906.         if (--len <= 0) {
  907.             *cp = 0;
  908.             log("string truncated: %s, linenum %d", str, linenum);
  909.             return;
  910.         }
  911.     }
  912.     *cp = 0;
  913. }
  914.  
  915.  
  916. /*
  917.  * Ascii to integer, with base check.
  918.  */
  919. atoii(s)
  920.     register char *s;
  921. {
  922.     int v;
  923.     char *c;
  924.  
  925.     if (isupper(*s))
  926.         *s = tolower(*s);
  927.     if (*s == 'x' || *s == 'h') {
  928.         c = "%x";
  929.         s++;
  930.     } else {
  931.         c = "%d";
  932.     }
  933.     if (sscanf(s, c, &v) != 1)
  934.         log("bad numeric field %s, linenum %d", s, linenum);
  935.     return (v);
  936. }
  937.  
  938.  
  939. /*
  940.  * Get an internet address as a hostname or dot format string.
  941.  */
  942. getiaddr(st)
  943.     register char *st;
  944. {
  945.     iaddr_t iaddr;
  946.     register struct hostent *host;
  947.  
  948.     if (isdigit(*st)) {
  949.         if ((iaddr = inet_addr(st)) == -1 || iaddr == 0)
  950.             log("bad ipaddress %s, linenum %d", st, linenum);
  951.     } else {
  952.         if ((host = gethostbyname(st)) == 0)
  953.             log("bad hostname %s, linenum %d", st, linenum);
  954.         bcopy(host->h_addr, (caddr_t)&iaddr, sizeof iaddr);
  955.     }
  956.     return (iaddr);
  957. }
  958.  
  959.  
  960. /*
  961.  * Get a short number or address.
  962.  */
  963. getashort(st)
  964.     register char *st;
  965. {
  966.     register char *cp;
  967.  
  968.     if ((cp = index(st, '.')) == 0)
  969.         return (atoii(st));
  970.     *cp++ = 0;
  971.     return ((atoii(st)<<8) | atoii(cp));
  972. }
  973.  
  974.  
  975. /*
  976.  * log an error message 
  977.  */
  978. log(fmt, args)
  979. char *fmt;
  980. {
  981.     FILE *fp;
  982.     long time(), tloc;
  983.     struct tm *tm, *localtime();
  984.  
  985.     if (debug)
  986.       fp = stderr;
  987.     else if (scanonly)
  988.       fp = stdout;
  989.     else if ((fp = fopen(atalkalog, "a+")) == NULL)
  990.       return;
  991.     time(&tloc);
  992.     tm = localtime(&tloc);
  993.     fprintf(fp, "%d/%d %02d:%02d ", tm->tm_mon + 1, tm->tm_mday,
  994.         tm->tm_hour, tm->tm_min);
  995.     _doprnt(fmt, &args, fp);
  996.     putc('\n', fp);
  997.     if (fp != stderr && fp != stdout)
  998.         fclose(fp);
  999. }
  1000.  
  1001. /*
  1002.  * getanet - scan through the table so far and find an appletalk network 
  1003.  * number. Called from the %x fields of the config structure
  1004.  *
  1005.  * flag field:
  1006.  *    arouteNet - match an IP address, scan for a net route that matches addr
  1007.  *    arouteKbox - scan for a route using this host
  1008.  *    arouteKbox|arouteETalk - scan for an Ethertalk net using this host.
  1009.  *
  1010.  * Limitations: Only one bridge can be configured with a given Ethertalk
  1011.  * network number this way. Network numbers referenced must be defined before
  1012.  * use.
  1013.  */
  1014. getanet(flags, ia)
  1015.      iaddr_t ia;
  1016. {
  1017.   register int i;
  1018.   struct anets *a;
  1019.  
  1020.   /* Scan table in reverse order - slightly more efficent */
  1021.   for(i = nanets-1; i >= 0; --i) {
  1022.     a = &anets[i];
  1023.  
  1024.     if ((flags == arouteNet &&
  1025.      ((a->flags & arouteNet) != 0 || (a->flags & arouteHost) != 0) &&
  1026.      match_net(a->flags, ia, a->iaddr)) ||
  1027.     (flags == arouteKbox &&
  1028.      (a->flags & arouteKbox|arouteEtalk) == arouteKbox &&
  1029.      a->iaddr == ia) ||
  1030.     (flags == arouteKbox|arouteEtalk &&
  1031.      (a->flags & flags) == flags &&
  1032.      a->iaddr == ia))
  1033.       return(a->net);
  1034.   } 
  1035.   log("unable to match appletalk net (%x), line %d\n", flags, linenum);
  1036.   return(0);
  1037. }
  1038.  
  1039. /*
  1040.  * match_net - match a network number, using mask field stored in
  1041.  * flags.
  1042.  */
  1043. match_net(flags, a1, a2)
  1044.      iaddr_t a1, a2;
  1045. {
  1046.   return((a1 & node_mask) == (a2 & node_mask));
  1047. }
  1048.  
  1049. char *
  1050. hostnameof(ipaddr)
  1051. struct in_addr ipaddr;
  1052. {
  1053.   struct hostent *host;
  1054.  
  1055.   host = gethostbyaddr(&ipaddr.s_addr, sizeof(ipaddr.s_addr), AF_INET);
  1056.   if (!host)
  1057.     return((char *)inet_ntoa(ipaddr));
  1058.   return(host->h_name);
  1059. }
  1060.  
  1061. zipinput()
  1062. {
  1063.   u_short buf[1000];
  1064.   u_short *bp;
  1065.   int icount;
  1066.   int len;
  1067.   u_char *p;
  1068.   char *zn;
  1069.   int zl;
  1070.   struct ZIP zipin;
  1071.   struct ZIP *z;
  1072.  
  1073.   icount = ntohs(aa.count);        /* remember incoming count */
  1074.   bcopy(aa.stuff, &zipin, sizeof(struct ZIP));
  1075.   if (zipin.command != zipQuery || zipin.count == 0)
  1076.     return(-1);
  1077.   /* get the list of networks */
  1078.   bcopy(aa.stuff+sizeof(struct ZIP), buf, zipin.count * sizeof(u_short));
  1079.   bp = buf;
  1080.   z = (struct ZIP *)aa.stuff;
  1081.   z->command = zipReply;
  1082.   z->count = 0;
  1083.   len = sizeof(struct ZIP);
  1084.   for (p = (u_char *)(z+1); len<512&&zipin.count; zipin.count--, bp++) {
  1085.     if ((zn = zoneof(*bp)) == NULL)
  1086.       continue;
  1087.     bcopy(bp, p, sizeof(u_short)); /* copy in network */
  1088.     p+= sizeof(u_short);    /* move along */
  1089.     len+= sizeof(u_short);    /* move along */
  1090.     zl = *p = strlen(zn);    /* get zone length */
  1091.     p++;            /* bounce */
  1092.     len++;
  1093.     z->count++;
  1094.     bcopy(zn, p, zl);        /* copy in zone name */
  1095.     p += zl;            /* bounce p ...*/
  1096.     len += zl;            /* ... and len */
  1097.   }
  1098.   return(len);
  1099. }
  1100.